#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>

#include "epoll.h"
#include "server.h"
#include "task_queue.h"
#include "tcp_init.h"
#include "thread_pool.h"
#include "worker.h"

int pipefd[2];

char ip[128];
char port[128];
int thread_num;
char root_path[128];

// TODO:
void signal_handler(int sg) {
  printf("sig num = %d\n", sg);
  write(pipefd[1], "1", 1);
}

int main(int argc, char *argv[]) {
  if (argc != 2) {
    printf("error arguments!\n");
    return -1;
  }

  // pipefd
  pipe(pipefd);

  // fork
  if (fork()) {
    printf("parent process\n");
    close(pipefd[0]);
    signal(SIGUSR1, signal_handler);
    wait(NULL);
    exit(0);
  }
  printf("child process\n");
  close(pipefd[1]);

  init_server(argv[1], ip, port, &thread_num, root_path);
  // thread_pool
  thread_pool_t thread_pool;
  int worker_num = thread_num;
  printf("worker_num = %d\n", worker_num);
  thread_pool_init(&thread_pool, worker_num);

  // create worker
  printf("start make worker!\n");
  make_worker(&thread_pool);
  printf("make worker done!\n");

  // tcp_init
  int sockfd;
  tcp_init(ip, port, &sockfd);

  // epoll
  int epfd = epoll_create(1);
  epoll_add(epfd, sockfd);
  epoll_add(epfd, pipefd[0]);
  struct epoll_event ready_set[2];

  printf("pipefd[0] = %d\n", pipefd[0]);

  // main loop
  while (1) {
    printf("while\n");
    int ready_num = epoll_wait(epfd, ready_set, 2, -1);

    for (int i = 0; i < ready_num; ++i) {
      printf("ready fd = %d\n", ready_set[i].data.fd);
      if (ready_set[i].data.fd == sockfd) {
        int netfd = accept(sockfd, NULL, NULL);
        printf("connect, netfd = %d\n", netfd);

        pthread_mutex_lock(&thread_pool.task_queue.mutex);
        task_enqueue(&thread_pool.task_queue, netfd);
        printf("main sent a new task!\n");
        pthread_cond_signal(&thread_pool.task_queue.cond);
        pthread_mutex_unlock(&thread_pool.task_queue.mutex);
      } else if (ready_set[i].data.fd == pipefd[0]) {
        printf("exit\n");
        pthread_mutex_lock(&thread_pool.task_queue.mutex);
        thread_pool.exit_flag = 1;
        pthread_cond_broadcast(&thread_pool.task_queue.cond);
        pthread_mutex_unlock(&thread_pool.task_queue.mutex);

        for (int j = 0; j < worker_num; ++j) {
          pthread_join(thread_pool.tid_arr[j], NULL);
        }

        printf("main thread is going to die!\n");
        pthread_exit(NULL);
      }
    }
  }
}
